package com.gitee.magic.framework.head.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;

import com.gitee.magic.core.exception.ApplicationException;
import com.gitee.magic.core.utils.ClassLoaderUtils;
import com.gitee.magic.core.utils.codec.Des;
import com.gitee.magic.core.utils.codec.DigestUtils;
import com.gitee.magic.core.utils.codec.Hex;

/**
 * @author start
 */
public class IoUtils extends FileUtils {

	public static final Integer BUFFER = 1024 * 8;

	/**
	 * 创建一个指定大小的文件
	 */
	public static boolean createFile(String filepath, String filename, long filesize) {
		if (!mkdirs(filepath)) {
			return false;
		}
		try (RandomAccessFile raf = new RandomAccessFile(filepath + File.separator + filename, "rw")) {
			raf.setLength(filesize);
			return true;
		} catch (FileNotFoundException e) {
			throw new ApplicationException(e);
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}
	
	public static void writeFileContent(File file,String content) {
		try (FileWriter fileWriter = new FileWriter(file);
				BufferedWriter out = new BufferedWriter(fileWriter);) {
			out.write(content);
	        out.flush();
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 根据文件完整路径获取文件的字符内容
	 */
	public static String getFileStringContent(String fileFullPath) {
		return new String(getFileBytes(new File(fileFullPath)));
	}

	/**
	 * 获取文件字节数组
	 */
	public static byte[] getFileBytes(File file) {
		int len = -1;
		byte[] b = new byte[BUFFER];
		try (FileInputStream fin = new FileInputStream(file);
				ByteArrayOutputStream baos = new ByteArrayOutputStream(8196);) {
			while ((len = fin.read(b)) != -1) {
				baos.write(b, 0, len);
			}
			return baos.toByteArray();
		} catch (FileNotFoundException e) {
			throw new ApplicationException(e);
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}
	
	/**
	 * inputstream转byte[]
	 * 
	 * @param is         流
	 * @param contentLen 大于零则设定内容长度,-1不设定长度
	 * @return
	 */
	public static byte[] inputStreamConvertBytes(InputStream is, int contentLen) {
		try (ByteArrayOutputStream baos = contentLen == -1 ? new ByteArrayOutputStream()
				: new ByteArrayOutputStream(contentLen);) {
			int readLen = -1;
			byte[] buff = new byte[1024 * 8];
			while ((readLen = is.read(buff)) != -1) {
				baos.write(buff, 0, readLen);
			}
			return baos.toByteArray();
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 通过给定的URL有本地文件名下载保存文件
	 */
	public static void downLoadFile(File destFile, String url) {
		try {
			destFile.createNewFile();
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
		int len = -1;
		byte[] buffer = new byte[BUFFER];
		URLConnection connection;
		try {
			URL u = new URL(url);
			connection = u.openConnection();
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
		connection.setReadTimeout(100000);
		try (BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));) {
			while ((len = bis.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
				bos.flush();
			}
		} catch (FileNotFoundException e) {
			throw new ApplicationException(e);
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 把输入流存储到本地
	 */
	public static String[] generateToLocal(InputStream inputStream, String savePath) {
		int len = -1;
		int fileLength = 0;
		byte[] buffer = new byte[BUFFER];
		MessageDigest md = DigestUtils.getMd5Digest();
		try (BufferedInputStream bis = new BufferedInputStream(inputStream);
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(savePath)));) {
			while ((len = bis.read(buffer)) != -1) {
				md.update(buffer, 0, len);
				bos.write(buffer, 0, len);
				bos.flush();
				fileLength = fileLength + len;
			}
			buffer = null;
			return new String[] {Hex.bytesToHex(md.digest()), String.valueOf(fileLength) };
		} catch (FileNotFoundException e) {
			throw new ApplicationException(e);
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 文件加密并存储
	 */
	public static String[] encryption(String oldpath, String encpath,String desKeyClsPath) {
		int len = -1;
		byte[] buffer = new byte[BUFFER];
		int fileLength = 0;
		try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(encpath)));) {
			MessageDigest md = DigestUtils.getSha1Digest();
			Cipher cipher = Cipher.getInstance(Des.ALGORITHM);
			cipher.init(Cipher.ENCRYPT_MODE,
					Des.getKey(ClassLoaderUtils.getResourcePath(desKeyClsPath)));
			try (CipherInputStream cis = new CipherInputStream(new FileInputStream(oldpath), cipher);) {
				while ((len = cis.read(buffer)) != -1) {
					md.update(buffer, 0, len);
					bos.write(buffer, 0, len);
					bos.flush();
					fileLength = fileLength + len;
				}
				return new String[] {Hex.bytesToHex(md.digest()), String.valueOf(fileLength) };
			}
		} catch (IOException e) {
			throw new ApplicationException(e);
		} catch (InvalidKeyException e) {
			throw new ApplicationException(e);
		} catch (ClassNotFoundException e) {
			throw new ApplicationException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new ApplicationException(e);
		} catch (NoSuchPaddingException e) {
			throw new ApplicationException(e);
		}
	}

	/**
	 * 文件下载输出
	 * 
	 * @param is      输入流
	 * @param out     输出流
	 * @param encrypt 加密标记
	 */
	public static void downloadToLocal(InputStream is, OutputStream out,String desKeyClsPath, Boolean encrypt) {
		int len = -1;
		byte[] buffer = new byte[BUFFER];
		try (BufferedOutputStream bos = new BufferedOutputStream(out);
				BufferedInputStream bis = new BufferedInputStream(is);) {
			if (encrypt) {
				// 边解密连输出
				Cipher cipher = Cipher.getInstance(Des.ALGORITHM);
				cipher.init(Cipher.DECRYPT_MODE,
						Des.getKey(ClassLoaderUtils.getResourcePath(desKeyClsPath)));
				try (CipherOutputStream cipherOutputStream = new CipherOutputStream(bos, cipher);) {
					while ((len = bis.read(buffer)) != -1) {
						cipherOutputStream.write(buffer, 0, len);
						cipherOutputStream.flush();
					}
				}
			} else {
				// 不加密输出
				while ((len = bis.read(buffer)) != -1) {
					bos.write(buffer, 0, len);
					bos.flush();
				}
			}
		} catch (IOException e) {
			throw new ApplicationException(e);
		} catch (NoSuchAlgorithmException e) {
			throw new ApplicationException(e);
		} catch (NoSuchPaddingException e) {
			throw new ApplicationException(e);
		} catch (InvalidKeyException e) {
			throw new ApplicationException(e);
		} catch (ClassNotFoundException e) {
			throw new ApplicationException(e);
		}
	}

}